/*
 * "The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is Todd A. Fisher code.
 *
 * The Initial Developer of the Original Code is Todd A. Fisher.
 * Portions created by the Initial Developer are Copyright (C) 2005
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): 
 *
 */

#include <string.h>
#include <nsMemory.h>
#include <nsStringAPI.h>
#include <nsIURL.h>
#include <nsILocalFile.h>
#include <nsComponentManagerUtils.h>
#include "QuickTrack.h"

/* Implementation file */
NS_IMPL_ISUPPORTS1_CI(QuickTrack, xmITrack)

QuickTrack::QuickTrack()
	:state(STOPPED),movie(0)
{
  /* member initializers and constructor code */
}

QuickTrack::~QuickTrack()
{
  /* destructor code */
	if( this->movie ){
		// free resource
		DisposeMovie( this->movie );
	}
}

/* AString getTitle (); */
NS_IMETHODIMP QuickTrack::GetTitle(nsAString & _retval)
{
	_retval = this->title;
	return NS_OK;;
}

/* AString getArtist (); */
NS_IMETHODIMP QuickTrack::GetArtist(nsAString & _retval)
{
	_retval = this->artist;
	return NS_OK;;
}

NS_IMETHODIMP QuickTrack::GetPath(nsAString & _retval)
{
  _retval = this->path;
  return NS_OK;
}

/* void setPosition (in long position); */
NS_IMETHODIMP QuickTrack::SetPosition(PRInt32 position)
{
	if( this->movie ){
		// TimeValue timeval = position * 600;
    TimeValue timeval = 
      round(position / 1000.0 * GetMovieTimeScale(this->movie));
		SetMovieTimeValue( this->movie, timeval );
	}
	return NS_OK;
}

/* long getPosition (); */
NS_IMETHODIMP QuickTrack::GetPosition(PRInt32 *_retval)
{
	if( this->movie ){
		// TimeValue timeval = GetMovieTime( this->movie, NULL ) / 600;
		// *_retval = timeval;// / duration;
    *_retval = (int)round(GetMovieTime(this->movie, NULL) * 1000.0 /
        GetMovieTimeScale(this->movie));
	}
  return NS_OK;
}

/* long getDuration (); */
NS_IMETHODIMP QuickTrack::GetDuration(PRInt32 *_retval)
{
	if( this->movie ){
    *_retval = (int)round(GetMovieDuration(this->movie) * 1000.0 /
        GetMovieTimeScale(this->movie));
	}
	return NS_OK;
}

/* short getState (); */
NS_IMETHODIMP QuickTrack::GetState(PRInt16 *_retval)
{
	*_retval = this->state;
	return NS_OK;
}

// see: http://developer.apple.com/qa/qa2001/qa1135.html
const UInt8 kUserDataIsText = 0xA9; // the copyright symbol
static bool
GetID3Tags( Movie movie, nsString &title, nsString &artist, nsString &album )
{
	OSErr err = noErr;
	OSType udType = 0;
	int dataCount = 0;
	UserData trackData = GetMovieUserData( movie );
	Handle textData = NewHandle(0);

	if( !trackData ){
		printf( "no tags!\n" );
		return false;
	}

	printf( "processing ID3Tags\n" );

	while( (udType = GetNextUserDataType( trackData, 0 ) ) ){
		printf( "tag type: %d\n", (int)udType );
		if( (udType>>24) != kUserDataIsText ){
			continue;
		}
		dataCount = CountUserDataType( trackData, udType );
		for( int i = 0; i < dataCount; ++i ){
			// FIXME: support for other languages??
			err = GetUserDataText( trackData, textData, udType, i, langEnglish );
			HLock( textData );
			printf("\n%c%c%c%c: %s\n", (char)(udType>>24),
						(char)(udType>>16),
						(char)(udType>>8),
						(char)udType, *textData);
			HUnlock( textData );
		}
	}
	printf( "processed ID3Tags\n" );
	DisposeHandle( textData );
	return true;
}

/* [noscript] void initTrack (in AString path); */
NS_IMETHODIMP QuickTrack::InitTrack(const nsAString & path)
{
	fprintf(stderr, "Initializing track\n");
	if (this->movie) {
    fprintf(stderr, "  ... Freeing previous movie\n");
		DisposeMovie(this->movie);
	}

  this->path = path;
  fprintf(stderr, "  ... Path = %s\n", NS_ConvertUTF16toUTF8(path).get());

	/*nsCString spec;
	url->GetSpec(spec);
	this->urlSpec = NS_ConvertUTF8toUTF16(spec);
  fprintf(stderr, "  ... URL = %s\n", spec.get());

  nsCString path;
  url->GetFilePath(path);
  fprintf(stderr, "  ... Path = %s\n", path.get());*/

  nsCOMPtr<nsILocalFile> file(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
  file->InitWithPath(path);
	if (!file) {
    fprintf(stderr, "  !!! OW! Something went wrong with this file...\n");
    return NS_ERROR_FAILURE;
  }

	OSErr err;
	short	movieRefNum;
	short resID = 0;
	Str255 name;
	Boolean changed;
	FSRef fsref;
	FSSpec movieFileSpec;

	// do some quick time stuff to get a handle for the movie
	err = FSPathMakeRef( (const UInt8*)NS_ConvertUTF16toUTF8( path ).get(), &fsref, 0 ); 
	if (err != noErr)
  {
    fprintf(stderr, "  !!! OW! FSPathMakeRef gave error %d\n", err);
		return NS_ERROR_FAILURE;
  }

	err = FSGetCatalogInfo( &fsref, kFSCatInfoVolume, NULL, NULL, &movieFileSpec, NULL );
	if( err != noErr ) {
    fprintf(stderr, "  !!! OW! FSGetCatalogInfo gave error %d\n", err);
		return NS_ERROR_FAILURE;
  }

	err = OpenMovieFile( &movieFileSpec, &movieRefNum, fsRdPerm );
	if( err != noErr ) {
    fprintf(stderr, "  !!! OW! OpenMovieFile gave error %d\n", err);
		return NS_ERROR_FAILURE;
  }

	err = NewMovieFromFile( &(this->movie), movieRefNum, &resID, name, newMovieActive, &changed );
	CloseMovieFile( movieRefNum );
	if( err != noErr ) {
    fprintf(stderr, "  !!! OW! NewMovieFromFile gave error %d\n", err);
		return NS_ERROR_FAILURE;
  }

  fprintf(stderr, "  ... Movie duration = %d\n",
      GetMovieDuration(this->movie));
  fprintf(stderr, "  ... Movie time scale = %d\n",
      GetMovieTimeScale(this->movie));
  fprintf(stderr, "  ... In milliseconds = %d\n",
      (int)round(GetMovieDuration(this->movie) * 1000.0 /
                 GetMovieTimeScale(this->movie)));
  
	return NS_OK;
}

/* [noscript] void play (); */
NS_IMETHODIMP QuickTrack::Play()
{
	if( this->movie && this->state != PLAYING ){
		this->state = PLAYING;
		StartMovie( this->movie );
	}
	return NS_OK;
}

/* [noscript] void pause (); */
NS_IMETHODIMP QuickTrack::Pause()
{
	if( this->movie && this->state == PLAYING ){
		this->state = PAUSED;
		StopMovie( this->movie );
	}
	return NS_OK;
}

/* [noscript] void stop (); */
NS_IMETHODIMP QuickTrack::Stop()
{
	if( this->movie && this->state != STOPPED ){
		this->state = STOPPED;
		StopMovie( this->movie );
		GoToBeginningOfMovie( this->movie );
	}
	return NS_OK;
}

/* [noscript] void setVolume (in float value); */
NS_IMETHODIMP QuickTrack::SetVolume(float value)
{
	if( this->movie ){
		// do some bit operations to convert float value to short
		short volume = 0;
		float percent = value / 100;
		float bitson = 16 * percent;
		
		for( int i = 0; i < bitson; ++i )
			volume &= ~(1 <<i);

		SetMovieVolume( this->movie, (short)value );
	}
	return NS_OK;
}

/* [noscript] float getVolume (); */
NS_IMETHODIMP QuickTrack::GetVolume(float *_retval)
{
	// FIXME: this won't return a proper value between 0 and 100
	if( this->movie )
		*_retval = (float)GetMovieVolume( this->movie );
	return NS_OK;
}
